#pragma once

#include <iostream>
#include <cstdio>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include "comm.hpp"

#define CREATER "creater"
#define USER "user"
const int gdefaultid = -1;
const int gsize = 4096;
const int gprojid = 0x66;
const int gmode = 0666;
const std::string gpathname = ".";

class Shm 
{
private:
    int _shmid;
    key_t _key;
    int _size;
    void * _start_mem;
    std::string _usertype;
    void CreateHelper(int flg)  // 创建共享内存
    {
        _shmid = shmget(_key, _size, flg);
        std::cout<<"shmget _shmid:"<<_shmid<<std::endl;
        if(_shmid < 0)
        {
            ERR_EXIT("shmget");
        }
        std::cout<<"shmget success"<<std::endl;
    }
    void Create()
    {
        CreateHelper(IPC_CREAT | IPC_EXCL | gmode);
    }
    void Get()
    {
        CreateHelper(IPC_CREAT);
    }
    void Attach()   // 共享内存链接
    {
        _start_mem = shmat(_shmid, nullptr, 0);
        if((long long)_start_mem < 0)
        {
            ERR_EXIT("shmat");
        }
        std::cout<<"attach success"<<std::endl;
    }

    void Detach()  //  解绑
    {
        int n = shmdt(_start_mem);
        if(n == 0)
        {
            std::cout<<"detach success"<< std::endl;
        }
    }

    void Destory()
    {
        if(_shmid == gdefaultid)
        {
            return ;
        }
        Detach();
        if(_usertype == CREATER)
        {
            int n = shmctl(_shmid, IPC_RMID,nullptr);
            if(n == 0)
            {
                std::cout<<_shmid<<"delete success"<<std::endl;
            }
            else 
            {
                ERR_EXIT("shmctl");
            }
        }
    }


public:
    Shm(const std::string &pathname, int projid, const std::string & usertype)
    : _shmid(gdefaultid),
      _size(gsize),
      _usertype(usertype),
      _start_mem(nullptr)
    {
        _key = ftok(pathname.c_str(), projid);   // 设置——key值  name和projid共同决定
        if(_key < 0)
        {
            ERR_EXIT("ftok");
        }
        if(_usertype == CREATER)
        {
            Create();
        }
        else if(_usertype == USER)
        {
            Get();
        }
        Attach();
    }
    void* VirtualAddr()
    {
        printf("%p\n",_start_mem);
        return _start_mem;
    }
    int Size()
    {
        return _size;
    }
    void Attr()
    {
        struct shmid_ds ds;         //   ipc_stat  cmd  获取ds  struct  属性信息
        int n = shmctl(_shmid, IPC_STAT, &ds);   
        printf("shm_size: %ld\n",ds.shm_segsz);
        printf("key: 0x%x\n", ds.shm_perm.__key);
    }

    ~Shm()
    {
        if(_usertype == CREATER)
        Destory();
    }
};

